using AnimCollections;

namespace DA.AnimGraph {

    internal static class PerkConstructure {
        public unsafe static void New<T>(out PerkLink* link, out T* perk, ref GraphBuffer buffer) where T : unmanaged {
            link = buffer.Malloc<PerkLink>();
            *link = new();

            perk = buffer.Malloc<T>();
            *perk = new();

            link->perkType = AGRuntimeTypeRegister.GetInstance().GetEnumByType(typeof(T));
        }

        /// <summary>
        /// link 已经有它的空间了
        /// </summary>
        public unsafe static void NewWithExistingLink<T>(PerkLink* link, out T* perk, ref GraphBuffer buffer) where T : unmanaged {
            *link = new();

            perk = buffer.Malloc<T>();
            *perk = new();

            link->perkType = AGRuntimeTypeRegister.GetInstance().GetEnumByType(typeof(T));
        }
    }

    public unsafe partial struct TimelinePerk {
        public static PerkLink* New(ref GraphBuffer buffer, in SetupData setupData) {
            PerkConstructure.New(out PerkLink* link, out TimelinePerk* perk, ref buffer);
            SetupFunction(link);
            SetupLink(perk, link);
            perk->Setup(setupData);
            return link;
        }
        public static PerkLink* NewWithExistingLink(PerkLink* link, ref GraphBuffer buffer, in SetupData setupData) {
            PerkConstructure.NewWithExistingLink(link, out TimelinePerk* perk, ref buffer);
            SetupFunction(link);
            SetupLink(perk, link);
            perk->Setup(setupData);
            return link;
        }
        public static void SetupFunction(PerkLink* link) {
            link->virtualFunction = AGRuntimeTypeRegister.GetInstance().GetPerkVirtualTable(AGRuntimeType.TimelinePerk);
            //link->EvaluateFunction = CachedEvaluate;
            //link->OnExitFunction = CachedOnExit;
        }
        public static PerkVirtualTable GetVirtualFunction() {
            var vt = new PerkVirtualTable();
            vt.EvaluateFunction = CachedEvaluate;
            vt.OnExitFunction = CachedOnExit;
            return vt;
        }
        internal static readonly PerkLink.EvaluateDelegate CachedEvaluate = Evaluate;
        internal static readonly PerkLink.OnExitDelegate CachedOnExit = OnExit;
    }

    public unsafe partial struct SyncGroupPerk {
        public static PerkLink* New(ref GraphBuffer buffer, in SetupData setupData) {
            PerkConstructure.New(out PerkLink* link, out SyncGroupPerk* perk, ref buffer);
            SetupFunction(link);
            SetupLink(perk, link);
            perk->Setup(setupData);
            return link;
        }
        public static PerkLink* NewWithExistingLink(PerkLink* link, ref GraphBuffer buffer, in SetupData setupData) {
            PerkConstructure.NewWithExistingLink(link, out SyncGroupPerk* perk, ref buffer);
            SetupFunction(link);
            SetupLink(perk, link);
            perk->Setup(setupData);
            return link;
        }
        public static void SetupFunction(PerkLink* link) {
            link->virtualFunction = AGRuntimeTypeRegister.GetInstance().GetPerkVirtualTable(AGRuntimeType.SyncGroupPerk);
            //link->EvaluateFunction = CachedEvaluate;
        }
        public static PerkVirtualTable GetVirtualFunction() {
            var vt = new PerkVirtualTable();
            vt.EvaluateFunction = CachedEvaluate;
            return vt;
        }
        internal static readonly PerkLink.EvaluateDelegate CachedEvaluate = Evaluate;
    }

    public unsafe partial struct CurveSamplerPerk {
        public static PerkLink* New(ref GraphBuffer buffer, in SetupData setupData) {
            PerkConstructure.New(out PerkLink* link, out CurveSamplerPerk* perk, ref buffer);
            SetupFunction(link);
            SetupLink(perk, link);
            perk->Setup(setupData);
            return link;
        }
        public static PerkLink* NewWithExistingLink(PerkLink* link, ref GraphBuffer buffer, in SetupData setupData) {
            PerkConstructure.NewWithExistingLink(link, out CurveSamplerPerk* perk, ref buffer);
            SetupFunction(link);
            SetupLink(perk, link);
            perk->Setup(setupData);
            return link;
        }
        public static void SetupFunction(PerkLink* link) {
            link->virtualFunction = AGRuntimeTypeRegister.GetInstance().GetPerkVirtualTable(AGRuntimeType.CurveSamplerPerk);
            //link->EvaluateFunction = CachedEvaluate;
            //link->PostEvaluateFunction = CachedPostEvaluate;
        }
        public static PerkVirtualTable GetVirtualFunction() {
            var vt = new PerkVirtualTable();
            vt.EvaluateFunction = CachedEvaluate;
            vt.PostEvaluateFunction = CachedPostEvaluate;
            return vt;
        }
        internal static readonly PerkLink.EvaluateDelegate CachedEvaluate = Evaluate;
        internal static readonly PerkLink.PostEvaluateDelegate CachedPostEvaluate = PostEvaluate;
    }
}
